import random, sys, time, math, pygame
from pygame.locals import *

FPS = 30
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
HALF_WINDOWWIDTH = WINDOWWIDTH // 2
HALF_WINDOWHEIGHT = WINDOWHEIGHT // 2

GRASSCOLOR = (24,255,0)
WHITE = (255,255,255)
RED = (255,0,0)

CAMERASLACK = 90
MOVERATE = 9
BOUNCERATE = 6
BOUNCEHEIGHT = 30
STARTSIZE = 25
WINSIZE = 200
INVULNERABLETIME = 2
GAMEOVERTIME = 4
MAXHEALTH = 3
NUMGRASS = 80
NUMSQUIRRELS = 30
SQUIRRELMINSPEED = 3
SQUIRRELMAXSPEED = 7
DIRCHANGEFREQ = 2
LEFT = '向左'
RIGHT = '向右'

def getRandomOffCameraPos(camerax, cameray, objWidth, objHeight):
    cameraRect = pygame.Rect(camerax, cameray, WINDOWWIDTH, WINDOWHEIGHT)
    while True:
        x = random.randint(camerax-WINDOWWIDTH, camerax+(WINDOWWIDTH*2))
        y = random.randint(cameray-WINDOWHEIGHT, cameray+(WINDOWHEIGHT*2))
        objRect = pygame.Rect(x, y, objWidth, objHeight)
        if not objRect.colliderect(cameraRect):
            return x, y
def makeNewGrass(camerax, cameray):
    gr = {}
    gr['grassImage'] = random.randint(0, len(GRASSIMAGES)-1)
    gr['width'] = GRASSIMAGES[0].get_width()
    gr['height'] = GRASSIMAGES[0].get_height()
    gr['x'], gr['y'] = getRandomOffCameraPos(camerax, cameray, gr['width'], gr['height'])
    gr['rect'] = pygame.Rect((gr['x'], gr['y'], gr['width'], gr['height']))
    return gr
def makeNewSquirrel(camerax, cameray):
    sq = {}
    generalSize = random.randint(5, 25)
    multiplier = random.randint(1, 3)
    sq['width'] = (generalSize + random.randint(0, 10)) * multiplier
    sq['height'] = (generalSize + random.randint(0, 10)) * multiplier
    sq['x'], sq['y'] = getRandomOffCameraPos(camerax, cameray, sq['width'], sq['height'])
    sq['movex'], sq['movey'] = getRandomVelocity(), getRandomVelocity()
    if sq['movex'] < 0:
        sq['surface'] = pygame.transform.scale(L_SQUIR_IMG, (sq['width'], sq['height']))
    else:
        sq['surface'] = pygame.transform.scale(R_SQUIR_IMG, (sq['width'], sq['height']))
    sq['bounce'] = 0
    sq['bouncerate'] = random.randint(10, 18)
    sq['bounceheight'] = random.randint(10, 50)
    return sq
def getRandomVelocity():
    speed = random.randint(SQUIRRELMINSPEED, SQUIRRELMAXSPEED)
    if random.randint(0, 1) == 0:
        return speed
    else:
        return - speed
def drawHealthMeter(currentHealth):
    for i in range(currentHealth):
        pygame.draw.rect(DISPLAYSURF, RED, (15, 5 + (10 * MAXHEALTH) - i * 10, 20, 10))
    for i in range(MAXHEALTH):
        pygame.draw.rect(DISPLAYSURF, WHITE, (15, 5 + (10 * MAXHEALTH) - i * 10, 20, 10), 1)
def runGame():
    invulnerableMode = False
    invulnerableStartTime = 0
    gameOverMode = False
    gameOverStartTime = 0
    winMode = False
    
    gameOverSurf = BASICFONT.render('Game Over', True, WHITE)
    gameOverRect = gameOverSurf.get_rect()
    gameOverRect.center = (HALF_WINDOWWIDTH, HALF_WINDOWHEIGHT)
    
    winSurf = BASICFONT.render('You have achieved OMEGA SQUIRREL!', True, WHITE)
    winSurf2 = BASICFONT.render('(Press "r" to restart.)', True, WHITE)
    winRect = winSurf.get_rect()
    winRect2 = winSurf2.get_rect()
    winRect.center = (HALF_WINDOWWIDTH, HALF_WINDOWHEIGHT)
    winRect2.center = (HALF_WINDOWWIDTH, HALF_WINDOWHEIGHT+30)
    
    camerax, cameray =0, 0
    playerObj = {'surface': pygame.transform.scale(L_SQUIR_IMG, (STARTSIZE, STARTSIZE)),
                 'facing': LEFT,
                 'size': STARTSIZE,
                 'x': HALF_WINDOWWIDTH,
                 'y': HALF_WINDOWHEIGHT,
                 'bounce': 0,
                 'health': MAXHEALTH}
    moveLeft, moveRight, moveUp, moveDown = False, False, False, False
    
    grassObjs = []
    for i in range(10):
        grassObjs.append(makeNewGrass(camerax, cameray))
        grassObjs[i]['x'] = random.randint(0, WINDOWWIDTH)
        grassObjs[i]['y'] = random.randint(0, WINDOWHEIGHT)
    squirrelObjs = []
    while True:
        if invulnerableMode and (time.time() - invulnerableStartTime > INVULNERABLETIME):
            invulnerableMode = False
            
        for sObj in squirrelObjs:
            sObj['x'] += sObj['movex']
            sObj['y'] += sObj['movey']
            sObj['bounce'] += 1
            if sObj['bounce'] > sObj['bouncerate']:
                sObj['bounce'] = 0
            if random.randint(0, 99) < DIRCHANGEFREQ:
                sObj['movex'] = getRandomVelocity()
                sObj['movey'] = getRandomVelocity()
                if sObj['movex'] > 0:
                    sObj['surface'] = pygame.transform.scale(R_SQUIR_IMG, (sObj['width'], sObj['height']))
                else:
                    sObj['surface'] = pygame.transform.scale(L_SQUIR_IMG, (sObj['width'], sObj['height']))
        
        for i in range(len(grassObjs)-1, -1, -1):
            if isOutsideActiveArea(camerax, cameray, grassObjs[i]):
                del grassObjs[i]
        while len(grassObjs) < NUMGRASS:
            grassObjs.append(makeNewGrass(camerax, cameray))
            
        for i in range(len(squirrelObjs)-1, -1, -1):
            if isOutsideActiveArea(camerax, cameray, squirrelObjs[i]):
                del squirrelObjs[i]
        while len(squirrelObjs) < NUMSQUIRRELS:
            squirrelObjs.append(makeNewSquirrel(camerax, cameray))
            
        playerCenterx = playerObj['x'] + playerObj['size'] // 2
        playerCentery = playerObj['y'] + playerObj['size'] // 2
        if (camerax + HALF_WINDOWWIDTH) - playerCenterx > CAMERASLACK:
            camerax = playerCenterx + CAMERASLACK - HALF_WINDOWWIDTH
        elif playerCenterx - (camerax + HALF_WINDOWWIDTH) > CAMERASLACK:
            camerax = playerCenterx - CAMERASLACK - HALF_WINDOWWIDTH
        if (cameray + HALF_WINDOWHEIGHT) - playerCentery > CAMERASLACK:
            cameray = playerCentery + CAMERASLACK - HALF_WINDOWHEIGHT
        elif playerCentery - (cameray + HALF_WINDOWHEIGHT) > CAMERASLACK:
            cameray = playerCentery - CAMERASLACK - HALF_WINDOWHEIGHT
        
        DISPLAYSURF.fill(GRASSCOLOR)
        for gObj in grassObjs:
            gRect = pygame.Rect((gObj['x'] - camerax,
                                 gObj['y'] - cameray,
                                 gObj['width'],
                                 gObj['height']))
            DISPLAYSURF.blit(GRASSIMAGES[gObj['grassImage']], gRect)
        
        for sObj in squirrelObjs:
            sObj['rect'] = pygame.Rect((sObj['x'] - camerax,
                                        sObj['y'] - cameray - getBounceAmount(sObj['bounce'], sObj['bouncerate'], sObj['bounceheight']),
                                        sObj['width'],
                                        sObj['height']))
            DISPLAYSURF.blit(sObj['surface'], sObj['rect'])
            

        
        playerObj['rect'] = pygame.Rect((playerObj['x'] - camerax,
                                         playerObj['y'] - cameray - getBounceAmount(playerObj['bounce'], BOUNCERATE, BOUNCEHEIGHT),
                                         playerObj['size'],
                                         playerObj['size']))
        
        flashIsOn = (round(time.time(), 1) * 10 % 2 == 1) #十分之一秒True, 十分之一秒False, 十分之一秒True, 十分之一秒False,...
        if not gameOverMode :
            if invulnerableMode:
                if flashIsOn:#丢命提醒：间隔十分之一秒闪烁
                    DISPLAYSURF.blit(playerObj['surface'], playerObj['rect'])
            else:
                    DISPLAYSURF.blit(playerObj['surface'], playerObj['rect'])
        drawHealthMeter(playerObj['health'])
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            elif event.type == KEYUP:
                if event.key == K_ESCAPE:
                    terminate()
                elif event.key in (K_UP, K_w):
                    moveUp = False
                elif event.key in (K_DOWN, K_s):
                    moveDown = False
                elif event.key in (K_LEFT, K_a):
                    moveLeft = False
                elif event.key in (K_RIGHT, K_d):
                    moveRight = False
            elif event.type == KEYDOWN:
                if event.key in (K_UP, K_w):
                    moveUp = True
                    moveDown = False
                elif event.key in (K_DOWN, K_s):
                    moveDown = True
                    moveUp = False
                elif event.key in (K_LEFT, K_a):
                    moveLeft = True
                    moveRight = False
                    if playerObj['facing'] == RIGHT:
                        playerObj['surface'] = pygame.transform.scale(L_SQUIR_IMG, (playerObj['size'], playerObj['size']))
                    playerObj['facing'] = LEFT
                elif event.key in (K_RIGHT, K_d):
                    moveRight = True
                    moveLeft = False
                    if playerObj['facing'] == LEFT:
                        playerObj['surface'] = pygame.transform.scale(R_SQUIR_IMG, (playerObj['size'], playerObj['size']))
                    playerObj['facing'] = RIGHT
                elif winMode and event.key == K_r:
                    return
        if gameOverMode:
            DISPLAYSURF.blit(gameOverSurf, gameOverRect)
            if time.time() - gameOverStartTime > GAMEOVERTIME:
                return
        else:
            if moveLeft:
                playerObj['x'] -= MOVERATE
            elif moveRight:
                playerObj['x'] += MOVERATE
            elif moveUp:
                playerObj['y'] -= MOVERATE
            elif moveDown:
                playerObj['y'] += MOVERATE
            for i in range(len(squirrelObjs)-1, -1, -1):
                sqObj = squirrelObjs[i]
                if 'rect' in sqObj :
                    if playerObj['rect'].colliderect(sqObj['rect']):
                        if playerObj['size']**2 >= sqObj['width'] * sqObj['height']:
                            playerObj['size'] += int((sqObj['width'] * sqObj['height']) ** 0.2) + 1
                            del squirrelObjs[i]
                            if playerObj['facing'] == LEFT:
                                playerObj['surface'] = pygame.transform.scale(L_SQUIR_IMG, (playerObj['size'], playerObj['size']))
                            elif playerObj['facing'] == RIGHT:
                                playerObj['surface'] = pygame.transform.scale(R_SQUIR_IMG, (playerObj['size'], playerObj['size']))
                            if playerObj['size'] > WINSIZE:
                                winMode = True
                        elif not invulnerableMode:
                            invulnerableMode = True
                            invulnerableStartTime = time.time()
                            playerObj['health'] -= 1
                            if playerObj['health'] == 0:
                                gameOverMode = True
                                gameOverStartTime = time.time()
        if (moveUp or moveDown or moveRight or moveLeft) or playerObj['bounce'] != 0:
            playerObj['bounce'] += 1
        if playerObj['bounce'] > BOUNCERATE:
            playerObj['bounce'] = 0
        if winMode:
            DISPLAYSURF.blit(winSurf, winRect)
            DISPLAYSURF.blit(winSurf2, winRect2)
        pygame.display.update()
        FPSCLOCK.tick(FPS)
def isOutsideActiveArea(camerax, cameray, obj):
    boundsLeftEdge = camerax - WINDOWWIDTH
    boundsTopEdge = cameray - WINDOWHEIGHT
    boundsRect = pygame.Rect(boundsLeftEdge, boundsTopEdge, WINDOWWIDTH*3, WINDOWHEIGHT*3)
    objRect = pygame.Rect(obj['x'], obj['y'], obj['width'], obj['height'])
    return not boundsRect.colliderect(objRect)
def getBounceAmount(currentBounce, bounceRate, bounceHeight):
    return int(math.sin( (math.pi / float(bounceRate)) * currentBounce ) * bounceHeight)
def terminate():
    pygame.quit()
    sys.exit()
def squirreleatsquirrel():
    global FPSCLOCK, DISPLAYSURF, BASICFONT, L_SQUIR_IMG, R_SQUIR_IMG, GRASSIMAGES
    pygame.init()
    FPSCLOCK = pygame.time.Clock()
    DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
    pygame.display.set_caption('大松鼠吃小松鼠')
    pygame.display.set_icon(pygame.image.load('res/gameicon.png'))
    BASICFONT = pygame.font.Font('freesansbold.ttf', 32)
    L_SQUIR_IMG = pygame.image.load('res/squirrel.png')
    R_SQUIR_IMG = pygame.transform.flip(L_SQUIR_IMG, True, False)
    GRASSIMAGES = []
    for i in range(1, 5):
        GRASSIMAGES.append(pygame.image.load('res/grass%s.png' % i) )
    while True:
        runGame()
if __name__ == '__main__':
    squirreleatsquirrel()